package net.takela.common.webflux.security.filter;

import net.takela.common.webflux.security.SecurityConfigProperties;
import net.takela.common.webflux.security.model.AuthUser;
import net.takela.common.webflux.security.service.AuthTokenManager;
import org.springframework.core.Ordered;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

import java.nio.file.AccessDeniedException;
import java.util.List;
import java.util.Optional;

/**
 * @author zhangyinghui
 * create at 2023/7/7
 * 认证是否携带token，且token是否有效。
 */
public class AppAuthenticationWebFilter implements WebFilter, Ordered, ReactiveAuthenticationFilter {

    private final AuthTokenManager authTokenManager;
    private SecurityConfigProperties securityConfigProperties;
    private static AntPathMatcher antPathMatcher = new AntPathMatcher();
    /**
     * 
     */
    public AppAuthenticationWebFilter(AuthTokenManager authTokenManager, SecurityConfigProperties securityConfigProperties) {
        this.authTokenManager = authTokenManager;
        this.securityConfigProperties = securityConfigProperties;
    }
    
    /**
     * 
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        //允许匿名访问就
        String path = exchange.getRequest().getURI().getPath();
        if (securityConfigProperties.getAnonymousUrls() != null){
            Optional<String> op = securityConfigProperties.getAnonymousUrls().stream().filter(e -> antPathMatcher.match(e, path)).findFirst();
            if (op.isPresent()){
                return chain.filter(exchange);
            }
        }
        AuthUser user = authTokenManager.parseUserInfoFromRequest(exchange.getRequest(), AuthUser.class);
        if (user != null) {
            //TODO://加载权限
            List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("0");
            user.setAuthorities(auths);
            Authentication authentication = new UsernamePasswordAuthenticationToken(
                    user, null, user.getAuthorities());

            return chain.filter(exchange).contextWrite(ReactiveSecurityContextHolder.withAuthentication(authentication));
        }
        return Mono.error(new AccessDeniedException("check token failed"));
    }

    
    /**
     * 
     */
    @Override
    public int getOrder() {
        return -1000000;
    }
}
